package org.ttitfly.workflow.engine.decider;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.apache.commons.beanutils.BeanUtils;
import org.ttitfly.workflow.SessionHolder;
import org.ttitfly.workflow.WFRequest;


/**
 * 条件计算决策器，判断逻辑条件表达式的返回值来决策
 * 
 * @author 潘海春
 * @version 2009-9-10
 */
public class ConditionsExpressionDecider implements Decider {

	/** 变量标识 */
	public static final String VAR = "$";

	/** 变量标识开始 */
	public static final String VAR_START = "{";

	/** 变量标识结束 */
	public static final String VAR_END = "}";

	/**
	 * 条件语句，由变量和逻辑运算符号组成
	 * 
	 * 如： "${money} le 100000" 表示的条件为"
	 * 变量money的值小于100000"，其中money的范围为请求变量的值，表达式不区分字符串还是数字，由程序根据上下文自行判断
	 */
	private String conditions;

	/**
	 * 构造函数
	 * 
	 * @param conditions
	 *            条件语句
	 */
	public ConditionsExpressionDecider(String conditions) {
		if (conditions != null && !"".equals(conditions = conditions.trim())) {
			this.conditions = conditions;
		}
	}

	@Override
	public boolean decide() {
		if (conditions == null) {
			// 如果没有条件则立即通过决策
			return true;
		}
		// 将表达式中的${}变量参数用请求数据中的实际变量值替换
		String expression = parse(conditions, SessionHolder.currentSession().getRequest());
		// 计算逻辑表达式
		return new ExpressionComputer(expression).logicResult();
	}

	/**
	 * 解释条件
	 * 
	 * @param condition
	 * @param request
	 * @return
	 */
	protected String parse(String condition, WFRequest request) {
		int i = condition.indexOf(VAR);
		while (i >= 0) {
			String var = condition.substring(i + 2, condition.indexOf(VAR_END));
			String varValue = "null";
			Object obj = null;
			try {
				obj = BeanUtils.getProperty(request.getAllVariables(), var);
			} catch (Exception e) {
				obj = null;
			}
			if (obj != null) {
				varValue = obj.toString();
			}
			condition = condition.replaceAll("\\" + VAR + "\\" + VAR_START + var + "\\" + VAR_END, varValue);
			i = condition.indexOf(VAR);
		}
		return condition;
	}

	/**
	 * 表达式计算器
	 * 
	 * @author 潘海春
	 * @version 2010-1-7
	 */
	public static class ExpressionComputer {

		/** 或 */
		private static final String OR = "||";

		/** 与 */
		private static final String AND = "&&";

		/** 大于等于 */
		private static final String GE = ">=";

		/** 大于 */
		private static final String GT = ">";

		/** 小于等于 */
		private static final String LE = "<=";

		/** 小于 */
		private static final String LT = "<";

		/** 等于 */
		private static final String EQ = "=";

		/** 不等于 */
		private static final String NE = "!=";

		/** 加 */
		private static final String ADD = "+";

		/** 减 */
		private static final String MINUS = "-";

		/** 乘 */
		private static final String MULTIPLY = "*";

		/** 除 */
		private static final String DIV = "/";

		/** 左括号 */
		private static final String L_BRACKET = "(";

		/** 右括号 */
		private static final String R_BRACKET = ")";

		/** 操作符优先级 */
		private static Map<String, Integer> expLevelMap = new HashMap<String, Integer>();
		static {
			expLevelMap.put(R_BRACKET, 0);
			expLevelMap.put(OR, 1);
			expLevelMap.put(AND, 2);
			expLevelMap.put(GE, 3);
			expLevelMap.put(GT, 3);
			expLevelMap.put(LE, 3);
			expLevelMap.put(LT, 3);
			expLevelMap.put(EQ, 3);
			expLevelMap.put(NE, 3);
			expLevelMap.put(ADD, 4);
			expLevelMap.put(MINUS, 4);
			expLevelMap.put(MULTIPLY, 5);
			expLevelMap.put(DIV, 5);
			expLevelMap.put(L_BRACKET, 6);
		}

		/** 表达式 */
		private String expression;

		/** 值栈 */
		private Stack<String> valueStack = new Stack<String>();

		/** 运算符栈 */
		private Stack<String> expStack = new Stack<String>();

		/**
		 * 构造函数
		 * 
		 * @param expression
		 */
		public ExpressionComputer(String expression) {
			if (expression == null || "".equals(this.expression = expression)) {
				throw new IllegalArgumentException("参数[expression]不能为空！");
			}
			// 先将">=", ">","<=", "<"等所有可能引起二义性的替换掉
			this.expression = this.expression.replaceAll(">=", " ge ")
					.replaceAll(">", " gt ").replaceAll("<=", " le ")
					.replaceAll("<", " lt ").replaceAll("==", " eq ")
					.replaceAll("!=", " ne ").replaceAll("=", " eq ");
			this.expression = expression
					.replaceAll("(\\s+[Oo][Rr]\\s+)|(\\|\\|)", " || ")
					.replaceAll("(\\s+[Aa][Nn][Dd]\\s+)|(&&)", " && ")
					.replaceAll("\\s+[Gg][Ee]\\s+", " >= ")
					.replaceAll("\\s+[Gg][Tt]\\s+", " > ")
					.replaceAll("\\s+[Ll][Ee]\\s+", " <= ")
					.replaceAll("\\s+[Ll][Tt]\\s+", " < ")
					.replaceAll("\\s+[Nn][Ee]\\s+", " != ")
					.replaceAll("\\s+[Ee][Qq]\\s+", " = ")
					.replaceAll("(\\s+[Aa][Dd][Dd]\\s+)|(\\+)", " + ")
					.replaceAll("(\\s+[Mm][Ii][Nn][Uu][Ss]\\s+)|(-)", " - ")
					.replaceAll("(\\s+[Mm][Uu][Ll][Tt][Ii][Pp][Ll][Yy]\\s+)|(\\*)", " * ")
					.replaceAll("(\\s+[Dd][Ii][Vv]\\s+)|(/)", " / ")
					.replaceAll("\\(", " ( ").replaceAll("\\)", " ) ")
					.replaceAll("\\s{2,}", " ");
		}

		/**
		 * 返回逻辑计算结果
		 * 
		 * @return
		 */
		public boolean logicResult() {
			compute();
			return Boolean.valueOf(valueStack.peek());
		}

		/**
		 * 数值结果
		 * 
		 * @return
		 */
		public double doubleResult() {
			compute();
			return Double.valueOf(valueStack.peek());
		}

		/**
		 * 计算结果
		 * 
		 * @return
		 */
		private void compute() {
			valueStack.clear();
			expStack.clear();
			String[] expressions = expression.split("\\s+");
			for (String str : expressions) {
				if (isExp(str)) {
					expCom(str);
				} else {
					valueStack.push(str);
				}
			}
			while (!expStack.isEmpty()) {
				comp();
			}
		}

		private void comp() {
			String rVal = valueStack.pop();
			String lVal = valueStack.pop();
			valueStack.push(caculate(lVal, expStack.pop(), rVal));
		}

		private void expCom(String str) {
			if (expStack.isEmpty()) {
				expStack.push(str);
			} else {
				String exp = expStack.peek();
				if (R_BRACKET.equals(str) && L_BRACKET.equals(exp)) {
					expStack.pop();
				} else {
					if (!(L_BRACKET.equals(exp)) && (expLevelMap.get(exp) >= expLevelMap.get(str))) {
						comp();
						expCom(str);
					} else {
						expStack.push(str);
					}
				}
			}
		}

		/**
		 * 计算一个值
		 * 
		 * @param lVal
		 * @param exp
		 * @param rVal
		 * @return
		 */
		private String caculate(String lVal, String exp, String rVal) {
			if (OR.equals(exp)) {
				if (Boolean.valueOf(lVal) || Boolean.valueOf(rVal)) {
					return "true";
				}
				return "false";
			}
			if (AND.equals(exp)) {
				if (Boolean.valueOf(lVal) && Boolean.valueOf(rVal)) {
					return "true";
				}
				return "false";
			}
			if (GE.equals(exp)) {
				if (Double.valueOf(lVal) >= Double.valueOf(rVal)) {
					return "true";
				}
				return "false";
			}
			if (GT.equals(exp)) {
				if (Double.valueOf(lVal) > Double.valueOf(rVal)) {
					return "true";
				}
				return "false";
			}
			if (LE.equals(exp)) {
				if (Double.valueOf(lVal) <= Double.valueOf(rVal)) {
					return "true";
				}
				return "false";
			}
			if (LT.equals(exp)) {
				if (Double.valueOf(lVal) < Double.valueOf(rVal)) {
					return "true";
				}
				return "false";
			}
			if (EQ.equals(exp)) {
				if (lVal.equals(rVal)) {
					return "true";
				}
				return "false";
			}
			if (NE.equals(exp)) {
				if (!lVal.equals(rVal)) {
					return "true";
				}
				return "false";
			}
			if (ADD.equals(exp)) {
				Double d = Double.valueOf(lVal) + Double.valueOf(rVal);
				return d.toString();
			}
			if (MINUS.equals(exp)) {
				Double d = Double.valueOf(lVal) - Double.valueOf(rVal);
				return d.toString();
			}
			if (MULTIPLY.equals(exp)) {
				Double d = Double.valueOf(lVal) * Double.valueOf(rVal);
				return d.toString();
			}
			if (DIV.equals(exp)) {
				Double d = Double.valueOf(lVal) / Double.valueOf(rVal);
				return d.toString();
			}
			return "";
		}

		/**
		 * 是否运算符
		 * 
		 * @param expString
		 * @return
		 */
		private boolean isExp(String expString) {
			return expLevelMap.get(expString) != null;
		}

	}

}
